package home.contaduria.domain;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class ExpenseDataOnDemand {
    private final Logger logger = LoggerFactory.getLogger(getClass());

    @PersistenceContext
    private EntityManager entityManager;
    private List<Expense> data;
    private Random random = new Random();

    private Client client;
    private ExpenseType expenseType;

    public List<Expense> getData() {
        return data;
    }

    public Expense getNewTransientExpense(int index) {
        Expense expense = new Expense();
        expense.setOperationSum(new BigDecimal(index));
        expense.setOperationDate(new Date());
        expense.setClient(client);
        expense.setType(expenseType);
        return expense;
    }

    public void init(Client client, ExpenseType expenseType) {
        logger.info("Initialize test data. Use default data size");
        this.client = client;
        this.expenseType = expenseType;

        data = findExpenseEntities(0, 10);
        if (data == null)
            throw new IllegalStateException("Find entries implementation for 'Expense' illegally returned null");
        if (!data.isEmpty()) {
            logger.info("Initialize test data with existing DB entities");
            return;
        }

        data = new ArrayList<Expense>();
        for (int i = 0; i < 10; i++) {
            Expense obj = getNewTransientExpense(i);
            entityManager.persist(obj);
            entityManager.flush();
            data.add(obj);
        }
        entityManager.flush();
        logger.info("Test data successfully initialized");
    }

    public void init(Client client, ExpenseType expenseType, int size) {
        logger.info("Initialize test data. Use data size {}", size);
        this.client = client;
        this.expenseType = expenseType;

        if (size < 1) {
            throw new IllegalArgumentException("Size value should not be less 1. Actual value is " + size);
        }
        data = findExpenseEntities(0, size);
        if (data == null)
            throw new IllegalStateException("Find entries implementation for 'ExpenseType' illegally returned null");
        if (!data.isEmpty() && data.size() >= size) {
            logger.info("Initialize test data with existing DB entities");
            return;
        }

        for (int i = data.size(); i < size; i++) {
            Expense obj = getNewTransientExpense(i);
            entityManager.persist(obj);
            entityManager.flush();
            data.add(obj);
        }
        entityManager.flush();
        logger.info("Test data successfully initialized");
    }

    private List<Expense> findExpenseEntities(int firstRow, int maxRows) {
        return entityManager.createQuery("SELECT e FROM Expense e", Expense.class).setFirstResult(firstRow)
                .setMaxResults(maxRows).getResultList();
    }

    public Expense getRandomExpense() {
        if (data == null) {
            throw new IllegalStateException("Method init was not invoked");
        }

        Expense obj = data.get(random.nextInt(data.size()));
        return entityManager.find(Expense.class, obj.getId());
    }

    public Expense getSpecificExpense(int index) {
        if (data == null) {
            throw new IllegalStateException("Method init was not invoked");
        }

        if (index < 0) {
            index = 0;
        }
        if (index > (data.size() - 1)) {
            index = data.size() - 1;
        }

        Expense expense = data.get(index);
        return entityManager.find(Expense.class, expense.getId());
    }
}
